package com.softdev.system.generator.controller;

import com.softdev.system.generator.entity.ClassInfo;
import com.softdev.system.generator.entity.ParamInfo;
import com.softdev.system.generator.entity.ReturnT;
import com.softdev.system.generator.service.GeneratorService;
import com.softdev.system.generator.util.MapUtil;
import com.softdev.system.generator.util.TableParseUtil;
import com.softdev.system.generator.util.ValueUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;

import java.io.BufferedWriter;
import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Date;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 代码生成控制器
 * @author wfl
 */
@Controller
@Slf4j
public class GeneratorController {
    @Autowired
    private ValueUtil valueUtil;

    @Autowired
    private GeneratorService generatorService;

    @GetMapping("/")
    public ModelAndView defaultPage() {
        return new ModelAndView("index").addObject("value",valueUtil);
    }
    @GetMapping("/index")
    public ModelAndView indexPage() {
        return new ModelAndView("index").addObject("value",valueUtil);
    }
    @GetMapping("/main")
    public ModelAndView mainPage() {
        return new ModelAndView("main").addObject("value",valueUtil);
    }

    @RequestMapping("/template/all")
    @ResponseBody
    public ReturnT getAllTemplates() throws Exception {
        String templates = generatorService.getTemplateConfig();
        return ReturnT.ok().put("templates",templates);
    }
    @PostMapping("/code/generate")
    @ResponseBody
    public ReturnT generateCode(@RequestBody ParamInfo paramInfo) throws Exception {
        //log.info(JSON.toJSONString(paramInfo.getOptions()));
        if (StringUtils.isEmpty(paramInfo.getTableSql())) {
            return ReturnT.error("表结构信息为空");
        }

        //1.Parse Table Structure 表结构解析
        ClassInfo classInfo = null;
        String dataType = MapUtil.getString(paramInfo.getOptions(),"dataType");
        if ("sql".equals(dataType)||dataType==null) {
            classInfo = TableParseUtil.processTableIntoClassInfo(paramInfo);
        }else if ("json".equals(dataType)) {
            //JSON模式：parse field from json string
            classInfo = TableParseUtil.processJsonToClassInfo(paramInfo);
            //INSERT SQL模式：parse field from insert sql
        } else if ("insert-sql".equals(dataType)) {
            classInfo = TableParseUtil.processInsertSqlToClassInfo(paramInfo);
            //正则表达式模式（非完善版本）：parse sql by regex
        } else if ("sql-regex".equals(dataType)) {
            classInfo = TableParseUtil.processTableToClassInfoByRegex(paramInfo);
            //默认模式：default parse sql by java
        }
        //2.Set the params 设置表格参数

        paramInfo.getOptions().put("classInfo", classInfo);
        paramInfo.getOptions().put("tableName", classInfo == null ? System.currentTimeMillis() : classInfo.getTableName());

        //log the generated table and filed size记录解析了什么表，有多少个字段
        //log.info("generated table :{} , size :{}",classInfo.getTableName(),(classInfo.getFieldList() == null ? "" : classInfo.getFieldList().size()));

        //3.generate the code by freemarker templates with parameters . Freemarker根据参数和模板生成代码
        Map<String, String> result = generatorService.getResultByParams(paramInfo.getOptions());
        log.info("result {}",result);
        log.info("table:{} - time:{} ", MapUtil.getString(result,"tableName"),new Date());
        //直接生成文件到项目
        genPathFile(paramInfo, result);
        return ReturnT.ok().put("outputJson",result);
    }

    private void genPathFile(ParamInfo paramInfo,Map<String, String> result){
        Map<String, Object> options = paramInfo.getOptions();
        String localProjectPath = (String)options.get("localProjectPath");
        String localPackagePre = (String)options.get("localPackagePre");
        if(StringUtils.isBlank(localProjectPath)){
            log.error("本地项目路径不存在,不生成文件");
            return;
        }
        if(StringUtils.isBlank(localPackagePre)){
            log.error("个性化父级路径不存在，不生成文件");
            return;
        }
        File locatProjectPathFile = new File(localProjectPath);
        if (!locatProjectPathFile.exists()) {
            log.error("本地项目路径不存在>>"+localProjectPath);
        }
        //通过表名获取文件名前缀
        String tableName = result.get("tableName");
        String fileName = camelName(tableName);
        //处理 最后字符串 roc-contrack-bill
        int i = localProjectPath.lastIndexOf("\\") + 1;
        String substring = localProjectPath.substring(i);
        String[] split = substring.split("-");
        String join = StringUtils.join(split, "\\");


        String rocControllerPath = localProjectPath+"\\"+substring+"-service" + "\\src\\main\\java\\com\\shiji\\"+join+"\\controller\\"+localPackagePre;
        String rocServicePath = localProjectPath +"\\"+substring+"-service" +  "\\src\\main\\java\\com\\shiji\\"+join+"\\service\\"+localPackagePre;
        String rocServiceImplPath = localProjectPath +"\\"+substring+"-service" +  "\\src\\main\\java\\com\\shiji\\"+join+"\\serviceimpl\\"+localPackagePre;
        String rocEntityPath = localProjectPath +"\\"+substring+"-bean" +  "\\src\\main\\java\\com\\shiji\\"+join+"\\entity\\"+localPackagePre;

        String filetype=(String) options.get("fileType");
        if("OneTable".equals(filetype)){
            String rocController = result.get("roc-controller");
            String rocService = result.get("roc-service");
            String rocServiceImpl = result.get("roc-service-impl");
            String rocEntity = result.get("roc-entity");
            String fileControllerName = fileName + "Controller.java";
            String fileServiceName = fileName + "Service.java";
            String fileServiceImplName = fileName + "ServiceImpl.java";
            String fileEntityName = fileName + ".java";
            genFile(rocControllerPath,fileControllerName,rocController);
            genFile(rocServicePath,fileServiceName,rocService);
            genFile(rocServiceImplPath,fileServiceImplName,rocServiceImpl);
            genFile(rocEntityPath,fileEntityName,rocEntity);


        }else if("ManyTabelPre".equals(filetype)){
            String rocController = result.get("roc-head-controller");
            String rocService = result.get("roc-head-service");
            String rocServiceImpl = result.get("roc-head-service-impl");
            String rocEntity = result.get("roc-head-entity");
            String fileControllerName = fileName + "Controller.java";
            String fileServiceName = fileName + "Service.java";
            String fileServiceImplName = fileName + "ServiceImpl.java";
            String fileEntityName = fileName + ".java";
            genFile(rocControllerPath,fileControllerName,rocController);
            genFile(rocServicePath,fileServiceName,rocService);
            genFile(rocServiceImplPath,fileServiceImplName,rocServiceImpl);
            genFile(rocEntityPath,fileEntityName,rocEntity);

        }else if("ManyTabelSon".equals(filetype)){
            String rocEntity = result.get("roc-item-entity");
            String fileEntityName = fileName + ".java";
            genFile(rocEntityPath,fileEntityName,rocEntity);
        }
    }
    private void genFile(String filepath,String fileName,String filecontext){
        File file = new File(filepath);
        if (!file.exists()) {
            file.mkdir();
        }
        filepath = filepath + "\\" + fileName;
        Path path = Paths.get(filepath);
        // 使用newBufferedWriter创建文件并写文件
        // 这里使用了try-with-resources方法来关闭流，不用手动关闭
        try (BufferedWriter writer =
                     Files.newBufferedWriter(path, StandardCharsets.UTF_8)) {
            writer.write(filecontext);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
    /**
     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空，则返回空字符串。</br>
     * 例如：HELLO_WORLD->HelloWorld
     * @param name 转换前的下划线大写方式命名的字符串
     * @return 转换后的驼峰式命名的字符串
     */
    public static String camelName(String name) {
        StringBuilder result = new StringBuilder();
        // 快速检查
        if (name == null || name.isEmpty()) {
            // 没必要转换
            return "";
        } else if (!name.contains("_")) {
            // 不含下划线，仅将首字母小写
            return name.substring(0, 1).toUpperCase() + name.substring(1);
        }
        // 用下划线将原始字符串分割
        String camels[] = name.split("_");
        for (String camel :  camels) {
            // 跳过原始字符串中开头、结尾的下换线或双重下划线
            if (camel.isEmpty()) {
                continue;
            }
            // 处理真正的驼峰片段
            if (result.length() == 0) {
                // 第一个驼峰片段，全部字母都小写
                result.append(camel.toLowerCase());
            } else {
                // 其他的驼峰片段，首字母大写
                result.append(camel.substring(0, 1).toUpperCase());
                result.append(camel.substring(1).toLowerCase());
            }
        }
        String nameChange = result.toString();
        String resultEnd=nameChange.substring(0, 1).toUpperCase() + nameChange.substring(1);
        return resultEnd;

    }

}
